﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace ScreenCapture.Base
{
    /// <summary>
    /// UI界面通知属性类,继承这个类的属性可以实现UI通知功能
    /// </summary>
    public class NotifyPropertyChanged : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // 触发(调用)属性更改事件
        protected void RaisePropertyChanged(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

        // 属性更改的时候被调用,它内部再去调用触发属性更改事件
        // [CallerMemberName] 这个特性表示这个参数PropertyName可以不传递参数,
        // 当不传递参数的时候编译器会自动将PropertyName这个形参赋值为调用者可能是对象
        // 属性或者是方法的所对应的名称. 比如调用属性为Person.Name,则PropertyName会自动
        // 赋值为Name
        protected void OnPropertyChanged([CallerMemberName] string PropertyName = null)
        {
            RaisePropertyChanged(PropertyName);
        }

        /// <summary>
        /// 触发某个对象的所有的属性更改,比如Person类下面有Name属性,和Age属性,如果在Name属性设置那里调用了
        /// RaisePropertyChanged("")表示的是这个Person类的所有的属性都发生了更改.
        /// 这对于UI中绑定了多个属性,并且需要在一个属性改变时更新所有绑定的场景非常有用.
        /// </summary>
        protected void RaiseAllChanged()
        {
            RaisePropertyChanged("");
        }

        // 封装Set方法,泛型方法,里面有一个比较器,去比较Field的值是否要发生更改
        // 如果发生更改就更改Field的值,并且通知UI属性发生了更改.
        protected bool Set<T>(ref T Field, T Value, [CallerMemberName] string PropertyName = null)
        {

            /*
             * EqualityComparer<T>.Default获取到的是一个比较器,这个比较器可以比较各种类型是否相等.
             *1) 比较数值,会根据值比较规则判断
             *2) 比较引用类型,会根据是否是同一个对象进行判断
             *3) 比较字符串,有自己特有的规则去比较
             *4) 可以比较两个Null值,为相等,而使用==操作符比较两个null值会得到false.
             *5) 这个比较器类型安全,你不错误的将一个int值和一个string值进行比较,以为编译器会发现这个错误
             */
            if (EqualityComparer<T>.Default.Equals(Field, Value))
                return false;

            Field = Value;
            RaisePropertyChanged(PropertyName);
            return true;
        }

    }
}
